import datetime
import logging
import os
from logging.handlers import RotatingFileHandler


class Logger:
    def __init__(self, log_file, level=logging.INFO, disable=False):
        """
        create a logger object

        Args:
            log_file (str): the path to the log file
            level (int): the logging level, options are logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL
            disable (bool): if True, do not log anything
        """
        self.disable = disable

        # if it's a filename, save log file in log directory
        if "/" not in log_file:
            log_file = "log/" + log_file
        log_dir = os.path.dirname(log_file)
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        self.log_file = log_file

        # init loggers
        self._init_loggers(level)

    def _init_loggers(self, level, name=None):
        # create a logger object
        name = name or __name__

        naive_logger = logging.getLogger(name + "_naive")
        naive_logger.setLevel(level)
        # naive handler, no formatter
        naive_handler = RotatingFileHandler(
            self.log_file, maxBytes=1 * 1024 * 1024, backupCount=10, encoding="utf-8"
        )
        naive_handler.setLevel(level)
        naive_logger.addHandler(naive_handler)
        self.naive_logger = naive_logger

        # debug, info logger
        logger = logging.getLogger(name + "_info")
        logger.setLevel(level)
        fh = RotatingFileHandler(self.log_file, maxBytes=1 * 1024 * 1024, backupCount=10, encoding="utf-8")
        fh.setLevel(level)
        # create formatter
        formatter = logging.Formatter(
            "[%(asctime)s - %(levelname)s]: %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
        )
        fh.setFormatter(formatter)
        logger.addHandler(fh)
        self.info_logger = logger

        # warning, error, critical logger
        logger = logging.getLogger(name + "_warn")
        logger.setLevel(level)
        handler = RotatingFileHandler(
            self.log_file, maxBytes=1 * 1024 * 1024, backupCount=10, encoding="utf-8"
        )
        handler.setLevel(level)
        # create formatter
        formatter = logging.Formatter(
            "[%(levelname)s - %(asctime)s]: %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
        )
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        self.warn_logger = logger

    def _process_messages(self, messages):
        if len(messages) == 1:
            message = str(messages[0])
        else:
            messages = [str(message) for message in messages]
            message = " ".join(messages)
        return message

    # define a decorator to disable logging
    def check_logging_open_status(func):
        def wrapper(self: "Logger", *args, **kwargs):
            if self.disable:
                return
            show_time = kwargs.pop("time", False)
            if show_time:
                self.naive_logger.critical("TIME: %s", str(datetime.datetime.now()))
            return func(self, *args, **kwargs)

        return wrapper

    @check_logging_open_status
    def log(self, *messages, **kwargs):
        """
        equivalent to info function, but log the message without formatting.
        """
        message = self._process_messages(messages)
        self.naive_logger.info(message, **kwargs)

    @check_logging_open_status
    def debug(self, *messages, **kwargs):
        message = self._process_messages(messages)
        self.info_logger.debug(message, **kwargs)

    @check_logging_open_status
    def info(self, *messages, **kwargs):
        message = self._process_messages(messages)
        self.info_logger.info(message, **kwargs)

    @check_logging_open_status
    def warning(self, *messages, **kwargs):
        message = self._process_messages(messages)
        self.warn_logger.warning(message, **kwargs)

    @check_logging_open_status
    def error(self, *messages, **kwargs):
        message = self._process_messages(messages)
        self.warn_logger.error(message, **kwargs)

    @check_logging_open_status
    def critical(self, *messages, **kwargs):
        message = self._process_messages(messages)
        self.warn_logger.critical(message, **kwargs)
